package com.hj.search.service.Impl;

import com.alibaba.fastjson.JSONObject;
import com.hj.common.constant.EsStatus;
import com.hj.common.exception.BusinessException;
import com.hj.common.util.StringUtils;
import com.hj.search.service.EsService;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;


@Service
public class EsServiceImpl implements EsService {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private static final String TYPE = "type";

    @Autowired
    private RestHighLevelClient client;


    //TODO : 索引操作

    /**
     * 创建索引
     *
     * @param indexName  索引名称
     * @param shards     分片数
     * @param replicas   副本数
     * @param properties 索引映射
     */
    @Override
    public boolean createIndex(String indexName, Integer shards, Integer replicas, Map<String, Map<String, String>> properties) {
        if (existsIndex(indexName)) {
            throw new BusinessException("该索引名称已存在");
        }
        //创建名称为indexName的索引
        CreateIndexRequest mufanIndex = new CreateIndexRequest(indexName);
        mufanIndex.settings(Settings.builder()
                .put("index.number_of_shards", shards)  //分片数
                .put("index.number_of_replicas", replicas)  //索引数
        );
        //设置索引映射
        if (!StringUtils.isEmpty(properties)) {
            JSONObject sourceJson = new JSONObject();
            sourceJson.put("properties", JSONObject.toJSON(properties));
            //设置映射
            mufanIndex.mapping(TYPE, sourceJson.toJSONString(), XContentType.JSON);
        }
        //创建索引
        CreateIndexResponse response = null;
        try {
            response = client.indices().create(mufanIndex);
        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessException("索引创建失败");
        }
        return response.isAcknowledged();
    }


    /**
     * 删除索引
     *
     * @param indexName 索引名称
     * @throws IOException
     */
    @Override
    public boolean deleteIndex(String indexName) {
        if (!existsIndex(indexName)) {
            throw new BusinessException("该索引名称不存在");
        }
        DeleteIndexRequest request = new DeleteIndexRequest(indexName);
        DeleteIndexResponse response = null;
        try {
            response = client.indices().delete(request);
        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessException("删除索引异常");
        }
        return response.isAcknowledged();
    }

    /**
     * 校验索引是否存在
     *
     * @param esIndex
     * @return
     */
    public boolean existsIndex(String esIndex) {
        boolean exist = false;
        try {
            Response response = client.getLowLevelClient().performRequest("HEAD", esIndex);
            exist = response.getStatusLine().getReasonPhrase().equals("OK");
        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessException("校验失败");
        }
        return exist;
    }

    //TODO : 文档更新操作

    /**
     * 添加或覆盖文档
     *
     * @param indexName : 索引名称
     * @param type      : 类型
     * @param data      : 数据
     * @param id        : null               -->   添加文档 _id为es随机生成的值
     *                  指定为已有数据的_id  -->   修改覆盖文档
     *                  指定为_id没有的值    -->   添加文件 且_id为指定值
     * @return
     */
    @Override
    public Map<String, Object> insertDoc(String indexName, String type, String id, Object data) {
        JSONObject jsonObject = (JSONObject) JSONObject.toJSON(data);
        IndexRequest indexRequest = new IndexRequest(indexName, type, id)
                .source(jsonObject.toJSONString(), XContentType.JSON);
        IndexResponse response = null;
        try {
            response = client.index(indexRequest);
        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessException("数据添加失败");
        }
        //返回元数据
        Map<String, Object> map = new HashMap<>();
        map.put("id", response.getId());
        map.put("version", response.getVersion());
        map.put("index", response.getIndex());
        map.put("type", response.getType());
        return map;
    }

    /**
     * 删除文档
     *
     * @param indexName
     * @param type
     * @param id
     * @return
     */
    @Override
    public String deleteDoc(String indexName, String type, String id) {
        DeleteRequest deleteRequest = new DeleteRequest(indexName, type, id);
        DeleteResponse deleteResponse = null;
        try {
            deleteResponse = client.delete(deleteRequest);
        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessException("删除文档失败");
        }
        if (deleteResponse.status() == RestStatus.NOT_FOUND) {
            return EsStatus.NOTFOUNE;
        }
        return EsStatus.SUCCESS;
    }

    /**
     * 局部修改文档
     *
     * @param indexName
     * @param type
     * @param id
     * @param data
     * @return
     */
    @Override
    public Map<String, Object> localUpdateDoc(String indexName, String type, String id, Object data) {
        JSONObject jsonObject = (JSONObject) JSONObject.toJSON(data);
        UpdateRequest updateRequest = new UpdateRequest(indexName, type, id)
                .doc(jsonObject.toJSONString(), XContentType.JSON);
        UpdateResponse response = null;
        try {
            response = client.update(updateRequest);
        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessException("修改失败");
        }
        //返回元数据
        Map<String, Object> map = new HashMap<>();
        map.put("id", response.getId());
        map.put("version", response.getVersion());
        map.put("index", response.getIndex());
        map.put("type", response.getType());
        return map;
    }

    //TODO : 文档搜索操作

    /**
     * 根据id搜索
     *
     * @param indexName
     * @param type
     * @param id
     * @return
     */
    @Override
    public GetResponse findById(String indexName, String type, String id) {
        GetRequest getRequest = new GetRequest(indexName, type, id);
        GetResponse response = null;
        try {
            response = client.get(getRequest);
        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessException("查询失败");
        }
        return response;
    }

    /**
     * 根据ids批量搜索
     *
     * @param indexName
     * @param type
     * @param ids
     * @return
     */
    @Override
    public SearchHits findByIds(String indexName, String type, String[] ids) {
        SearchRequest searchRequest = new SearchRequest(indexName);
        //构建查询条件
        if (StringUtils.isNotEmpty(ids)) {
            SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
            QueryBuilder queryBuilder = QueryBuilders.idsQuery().addIds(ids);
            sourceBuilder.query(queryBuilder);
            sourceBuilder.size(ids.length);
            sourceBuilder.sort(new FieldSortBuilder("_id"));//id排序

            searchRequest.source(sourceBuilder);
        }
        searchRequest.types(type);
        //发起请求
        SearchResponse searchResponse = null;
        try {
            searchResponse = client.search(searchRequest);
        } catch (IOException e) {
            e.printStackTrace();
        }
        SearchHits searchHits = searchResponse.getHits();
        return searchHits;
    }
}
